#!/usr/bin/python
# -*- coding: utf-8 -*-

__version__ = "0.1"
__autor__ = "Yassin Ezbakhe <yassin@ezbakhe.es>"

import xml.etree.cElementTree as etree

class XMLElement:
    """
    An XML node wrapper that allows access to children and attributes using
    a pythonic syntax. Each attribute and each child element is an object
    atribute (self.childTag). They can also be accessed using self[childKey],
    where childKey can be the child position (integer) or its tag (string).
    
    If an element has multiple children with the same tag, only the last one
    can be accessed as an atribute. The rest are only available as
    self[childPos]. The class is also iterable (for example, to get
    all children, list(self) can be used).
    
    The XML file is parsed using the ElementTree XML API.
    """
    
    def __init__(self, node):
        self._parse(node)
       
    def _parse(self, node):
        self.text = node.text
        self._tag = node.tag
        self._attribs = { }
        self._childrenTags = [ ]
        self._children = [ ]
        # set attributes
        for (attrib, value) in node.attrib.iteritems():
            self._attribs[attrib] = value
            setattr(self, attrib, value)
        # set children
        for child in node:
            if len(child.getchildren()) == len(child.attrib) == 0:
                childNode = child.text
            else:
                childNode = XMLElement(child)
            self._childrenTags.append(child.tag)
            self._children.append(childNode)
            setattr(self, child.tag, childNode)
            
    def __str__(self):
        return self.text
        
    def __repr__(self):
        s = "<XMLElement %s at %s>" % (self._tag, hex(id(self)))
        return s
        
    def __getitem__(self, item):
        """Get an element by position (integer) or by tag name (string)"""
        if type(item) == type(0):
            if 0 <= item < len(self._childrenTags):
                return self._children[item]
            else:
                raise IndexError
        elif type(item) == type(""):
            if item not in self._childrenTags:
                raise KeyError
            return getattr(self, item)
        else:
            raise KeyError

def fromString(string):
    """Parse an XML string and return an XMLElement object"""
    root = etree.fromstring(string)
    return XMLElement(root)
    
def fromFile(path):
    """Parse an XML file and return an XMLElement object"""
    root = etree.parse(path).getroot()
    return XMLElement(root)
